#!/usr/bin/pythonw
########################################################################
# wickddup.py - Wick Digital Dailies Uploader: SFTPs an arbitrary number
#	of files to a remote server.
#
# Created 2006.04.08 by Warren Young
#
# Copyright (c) 2006 by Pixel Corps.  This program may be used under
# the terms of the X11 license, a copy of which should have accompanied
# this program, in the LICENSE file.
########################################################################

import fncheck, gui, sftp, slate, util

import getopt, os, posixpath, sys


def RedirectOutputToLog():
	"""
	Open a debug log in the temp directory, and redirect stdout and
	stderr to it.
	"""

	logFile = '%s/wickddup-debug.txt' % (util.GetTempPath())
	try:
		sys.stderr = sys.stdout = open(logFile, 'w')
	except:
		print "Could not open log file '%s'!" % (logFile)


def usage():
	"""Print the program's usage message"""

	print """
usage: wickddup.py [-gmos]
        [-d local-dir] [-h hostname] [-p port] [-r remote-dir] [-u username]
        [-V INDEX=STRING]... files...

    Program behavior options:
      -d  set program's working directory
      -g  get upload parameters from GUI instead of command line
      -m  upload new / modified files only
      -o  suppress redirection of output streams to debug log
      -V  set literal string #INDEX used in checking filename part
          validity; INDEX must be from 1 to the number of defined
          file name verification parameters

    SFTP options:
      -h  host name of server to SFTP file to
      -p  port number on server to use (default is 22)
      -r  directory on server to place file into
      -u  user name on SFTP server
      -R  remote directory variable

    Slate info options:
      -s  generate slate XML file
      -E  element / shot name
      -J  project name
      -N  notes
      -S  scene name
      -U  arist name
    
    You can run the program in GUI mode (-g), in which case all other
    parameters come from the GUI.  Otherwise, you must give -h, -r and
    -u.  Everything else is optional.
"""


def ParseCommandLine(uploader):
	"""
	Parse the options and arguments given on the command line
	
	@type uploader: L{sftp.SFTPUploader}
	@param uploader: object to hold values we get on the command line,
	affecting the SFTP upload process

	@rtype: boolean
	@return: True if we encounter no errors in parsing the command line,
	and that we find sufficient parameters to go forward.
	"""

	# Slate Info Variables
	genSlate = False
	sltProject = None
	sltScene = None
	sltElement = None
	sltArtist = None
	sltNotes = None

	# Misc variables
	allowRedirect = True
	shouldRedirect = False

	## Parse options on command line
	try:
		# Get program options from argument file, if it is given
		opts = None
		args = None
		if len(sys.argv) == 2 and sys.argv[1][0] != '-':
			try:
				# We've apparently been given a .ddo file, so send
				# stdout and stderr to a debug log and then slurp
				# the options file's contents in.
				shouldRedirect = True
				argFile = open(sys.argv[1])
				sys.argv.pop()
				exec(argFile)
			except:
				print "Argument file %s does not exist!" % sys.argv[1]
				return False

		if not opts:
			# Check for the environment variable that forces us into GUI
			# mode.  Note that this doesn't happen if the program is
			# launched to service a ddo file.
			if 'WICKDDUP_GUI' in os.environ:
				shouldRedirect = True
				uploader.filePickerGUI = True
				opts = ()

			# Get program options from command line if we didn't already
			# grab them from the ddo file.
			if len(sys.argv) > 1:
				opts, args = getopt.getopt(sys.argv[1:], \
						"d:gh:mop:r:R:su:E:J:N:S:U:V:")
			elif not uploader.filePickerGUI:
				print "No arguments given!"
				usage()
				return False

		# Save data given as command line options, doing basic checks
		# on the values.
		for opt, val in opts:
			if opt == '-d':
				os.chdir(val)
			elif opt == '-g':
				uploader.filePickerGUI = True
				shouldRedirect = True
			elif opt == '-h':
				uploader.hostName = val
			elif opt == '-m':
				uploader.modOnly = True
			elif opt == '-o':
				allowRedirect = False
			elif opt == '-p':
				port = int(val)
				if port > 0 and port < 65536:
					uploader.port = port
				else:
					print "Ignoring out of range SFTP port. " + \
							"Must be between 1 and 65535!"
			elif opt == '-r':
				uploader.remoteDirRaw = val
			elif opt == '-R':
				uploader.remoteDirVar = val
			elif opt == '-s':
				genSlate = True
			elif opt == '-u':
				uploader.userName = val
			elif opt == '-E':
				sltElement = val
			elif opt == '-J':
				sltProject = val
			elif opt == '-N':
				sltNotes = val
			elif opt == '-S':
				sltScene = val
			elif opt == '-U':
				sltArtist = val
			elif opt == '-V':
				parts = val.split('=')
				if len(parts) >= 2:
					index = int(parts[0])
					value = '='.join(parts[1:])		# just in case...
					max = len(fncheck.literals)
					if index > max:
						print '-V argument index too high: max is', max
					elif index < 1:
						print '-V argument index', index, ' must be > 0'
					else:
						fncheck.literals[index - 1] = value
				else:
					print 'Bad -V argument: required form is INDEX=VALUE'

		# Redirect output streams if we seem to be running without a
		# console, and we're allowed to.
		if allowRedirect and shouldRedirect:
			RedirectOutputToLog()

		# Save non-option command line arguments as the list of files to
		# upload.
		if args:
			uploader.localFiles = args
		elif not uploader.filePickerGUI:
			print 'No files to upload!'
			usage()
			return False

	except getopt.GetoptError, err:
		print 'Option parsing error: ' + str(err)
		usage()
		return False

	## We've parsed the individual command line options, so now check
	## that they are, collectively, reasonable.
	if uploader.RemoteDir():
		# Make sure we have enough info to get onto the file server.
		if uploader.filePickerGUI:
			print 'File picker GUI mode selected...'
		elif not (uploader.hostName and uploader.RemoteDir() and
				uploader.userName):
			print 'Not enough information to infer upload location. You must'
			print 'give either -g, or -h, -r, and -u.'
			usage()
			return False

		# Build the remote paths we'll use when uploading the files
		if len(uploader.localFiles) > 0:
			uploader.BuildRemotePaths()

		# Call function to generate slate, if proper variables are specified
		if genSlate:
			if sltProject and sltScene and sltElement and sltArtist:
				xmlFile = slate.Generate(sltProject, sltScene,
						sltElement, sltArtist, sltNotes, uploader)
				if xmlFile:
					uploader.localFiles.append(xmlFile)
					uploader.remoteFiles.append(posixpath.join(
							uploader.RemoteDir(),
							os.path.basename(xmlFile)))
			else:
				print 'You must specify -J, -S, -E, -U, and -N to generate a slate'
				usage()
				return False

		return True
	elif uploader.filePickerGUI:
		return True
	else:
		print 'You must give either -g or -r'
		usage()
		return False


def main():
	uploader = sftp.SFTPUploader()
	if ParseCommandLine(uploader):
		gui.StartApp(uploader)
	else:
		sys.exit(1)


if __name__ == "__main__": main()

